home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / waisgate / cutil.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  23KB  |  1,000 lines

  1. /* Wide AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.  
  4.   
  5.    3.26.90    Harry Morris, morris@think.com
  6.    4.11.90  HWM - generalized conditional includes (see c-dialect.h)
  7.    7/19/91  speed up substrcmp by ses@ccgr.technion.ac.il (Simon E Spero)
  8.  *
  9.  * $Log: cutil.c,v $
  10.  * Revision 1.24.1.1  1992/07/11  00:55:47  curtisg
  11.  * Changes for SCO UNIX
  12.  *
  13.  * Revision 1.24  92/03/28  19:53:39  jonathan
  14.  * Removed useless ifdef BSD in cprintf
  15.  * 
  16.  * Revision 1.23  92/03/07  19:44:39  jonathan
  17.  * ANSIfied arguments.
  18.  * 
  19.  * Revision 1.22  92/03/04  16:14:23  jonathan
  20.  * Added include <ctype.h> for isalnum.
  21.  * 
  22.  * Revision 1.21  92/02/21  11:03:15  jonathan
  23.  * Fixed $Log.
  24.  * 
  25.  * Revision 1.20  92/02/21  11:02:02  jonathan
  26.  * Added wais_log_level, RCSIdent
  27.  * 
  28.  * Revision 1.19  92/02/16  21:24:54  jonathan
  29.  * Added code for vprintf, if needed (like for old BSD).
  30.  * 
  31.  * Revision 1.18  92/02/12  14:33:26  morris
  32.  * made string_downcase not die when passed NULL
  33.  * 
  34.  * Revision 1.17  92/02/12  13:16:21  jonathan
  35.  * Added $Log so RCS will put the log message in the header
  36.  * 
  37.  *
  38. */
  39.  
  40. #ifndef lint
  41. static char *RCSid = "$Header: /y/src/wais/wais-8-b5/ir/RCS/cutil.c,v 1.24.1.1 1992/07/11 00:55:47 curtisg Exp curtisg $";
  42. #endif
  43.  
  44. #define _C_C_util_
  45.  
  46. #include "cutil.h"
  47. #include "panic.h"
  48.  
  49. #include <ctype.h>
  50. #include <string.h>
  51.  
  52. #if defined(M_XENIX) && !defined(M_UNIX)
  53. /* perhaps this should be in ustubs.h */
  54. #include <malloc.h>
  55. char* calloc();
  56. #endif /* def M_XENIX */
  57.  
  58. /*----------------------------------------------------------------------*/
  59.  
  60. /*#define MEMORY_ACCOUNTING*/
  61.  
  62. #ifdef MEMORY_ACCOUNTING
  63. #undef s_checkPtr
  64. #define s_checkPtr(ptr) fs_checkPtr(ptr)
  65. static FILE* memRecord = NULL;
  66. static void prepMemAcct _AP((void));
  67. static void 
  68. prepMemAcct()
  69. {
  70.   if (memRecord == NULL)
  71.     memRecord = s_fopen("MemoryAccounting","w");
  72. }
  73. static void flushMemAcct _AP((void));
  74. static void 
  75. flushMemAcct()
  76. {
  77.   fflush(memRecord);
  78. }
  79. #define tickles 0
  80. static char*     badPtr    = (char*)-1;
  81. static size_t    badSize    = -1;
  82. #endif /* def MEMORY_ACCOUNTING */
  83.  
  84. /*----------------------------------------------------------------------*/
  85.  
  86. void
  87. fs_checkPtr(ptr)
  88. void* ptr;
  89. /* If the ptr is NULL, give an error */
  90. #ifdef MEMORY_ACCOUNTING
  91. static char** ptrs = NULL;
  92. long i;
  93. static Boolean  doneSetup = false;
  94. if (doneSetup == false)
  95. {
  96. #ifdef THINK_C
  97. Debugger();
  98. #endif /* def THINK_C */
  99. doneSetup = true;
  100. }
  101. #endif /* def MEMORY_ACCOUNTING */
  102.  
  103.   if (ptr == NULL)
  104.     panic("checkPtr found a NULL pointer");
  105.  
  106. #ifdef MEMORY_ACCOUNTING
  107. /* look for specific ptr (useful when tracking un-freed memory) */
  108. if (ptr == badPtr) warn("checking found bad ptr"); 
  109. /* tickle a memory bug */
  110. if (ptrs == NULL && tickles > 0)
  111.   ptrs = (char**)malloc((size_t)tickles * sizeof(char*));
  112. for (i = 0; i < tickles; i++)
  113. { ptrs[i] = malloc((size_t)5);
  114. }
  115. for (i = 0; i < tickles; i++)
  116. { free(ptrs[i]);
  117. }
  118. #endif /* def MEMORY_ACCOUNTING */
  119.  
  120. }
  121.  
  122. /*----------------------------------------------------------------------*/
  123.  
  124. void*
  125. fs_malloc(size)
  126. size_t size;
  127. /* does safety checks and optional accounting */
  128.   register void* ptr = NULL;
  129.  
  130.   if(!size) return(NULL);
  131.  
  132. #ifdef THINK_C
  133.   ptr = (void*)NewPtr((long)size);
  134.   s_checkPtr(ptr);
  135.   memset(ptr,0,(size_t)size);    /* zero it */
  136. #else  
  137.   ptr = (void*)calloc((size_t)size,(size_t)1);
  138.   s_checkPtr(ptr);
  139. #endif
  140.   
  141. #ifdef MEMORY_ACCOUNTING
  142.   /* look for specific size (useful when tracking un-freed memory) */
  143.   if (size == badSize)
  144.     warn("bad size in malloc");
  145.   
  146.   prepMemAcct();
  147.   fprintf(memRecord,"malloced %lu bytes at %lu\n",size,ptr);
  148.   flushMemAcct();
  149. #endif
  150.  
  151.   return(ptr);
  152. }
  153.  
  154. /*----------------------------------------------------------------------*/
  155.  
  156. void*
  157. fs_realloc(ptr,size)
  158. void* ptr;
  159. size_t size;
  160. /* does safety checks and optional accounting 
  161.    note - we don't know how big ptr's memory is, so we can't ensure
  162.    that any new memory allocated is NULLed!
  163.  */
  164.   register void* nptr = NULL;
  165.   
  166.   if (ptr == NULL)        /* this is really a malloc */
  167.     return(s_malloc(size));
  168.     
  169. #ifdef THINK_C
  170.   nptr = NewPtr(size);        /* need to make a copy */ 
  171.   s_checkPtr(nptr);
  172.   BlockMove(ptr,nptr,size);    /* move the old contents into it */
  173.   DisposPtr(ptr);            /* get rid of the old ones */
  174. #else
  175.   nptr = (void*)realloc(ptr,size);
  176.   s_checkPtr(ptr);
  177. #endif  
  178.    
  179. #ifdef MEMORY_ACCOUNTING
  180.   /* look for specific size (useful when tracking un-freed memory) */
  181.   if (size == badSize) 
  182.     warn("bad size in realloc");
  183.   
  184.   prepMemAcct();
  185.   fprintf(memRecord,"realloced %lu bytes at %lu from %lu\n",size,nptr,ptr);
  186.   flushMemAcct();
  187. #endif
  188.  
  189.   return(nptr);
  190. }
  191.  
  192. /*----------------------------------------------------------------------*/
  193.  
  194. void
  195. fs_free(ptr)
  196. void* ptr;
  197. /* does safety checks and optional accounting */
  198. {
  199. #ifdef MEMORY_ACCOUNTING
  200.   prepMemAcct();
  201.   /* note that the sizeof a pointer is always 4.  If only we could find out
  202.      how much space that pointer was pointing to.  Oh well, this is a place
  203.      holder for now
  204.    */
  205.   fprintf(memRecord,"freed %lu bytes at %lu\n",(size_t)sizeof(ptr),ptr);
  206.   flushMemAcct();
  207.  
  208.   /* look for specific ptr (useful when tracking un-freed memory) */
  209.   if (ptr == badPtr) warn("bad ptr in free");
  210. #endif
  211.  
  212.   if (ptr != NULL)        /* some non-ansi compilers/os's cant handle freeing null */
  213.     {                /* if we knew the size of this block of memory, we could clear it - oh well */
  214. #ifdef THINK_C
  215.       DisposPtr(ptr);
  216. #else
  217.       free(ptr);
  218. #endif
  219.     }
  220. }
  221.  
  222. /*----------------------------------------------------------------------*/
  223.  
  224. char*
  225. s_strdup(s)
  226. char* s;
  227.  
  228. /* return a copy of s.  This is identical to the standard library routine
  229.    strdup(), except that it is safe.  If s == NULL or malloc fails, 
  230.    appropriate action is taken.
  231.  */
  232. {
  233.   unsigned long len;
  234.   char* copy = NULL;
  235.   
  236.   if (s == NULL)        /* saftey check to postpone stupid errors */
  237.     return(NULL);
  238.     
  239.   len = strlen(s);        /* length of string - terminator */
  240.   copy = (char*)s_malloc((size_t)(sizeof(char)*(len + 1)));
  241.   strncpy(copy,s,len + 1);
  242.   return(copy);
  243. }
  244.  
  245. /*----------------------------------------------------------------------*/
  246.  
  247. char*
  248. fs_strncat(dst,src,maxToAdd,maxTotal)
  249. char* dst;
  250.    char* src;
  251.    size_t maxToAdd;
  252.    size_t maxTotal;
  253.  
  254. /* like strncat, except the fourth argument limits the maximum total 
  255.    length of the resulting string
  256.  */
  257. {
  258.   size_t dstSize = strlen(dst);
  259.   size_t srcSize = strlen(src);
  260.   
  261.   if (dstSize + srcSize < maxTotal) /* use regular old strncat */
  262.     return(strncat(dst,src,maxToAdd));
  263.   else
  264.     { size_t truncateTo = maxTotal - dstSize - 1;
  265.       char   saveChar;
  266.       char*  result = NULL;
  267.  
  268.       saveChar = src[truncateTo];
  269.       src[truncateTo] = '\0';
  270.       result = strncat(dst,src,maxToAdd);
  271.       src[truncateTo] = saveChar;
  272.       return(result);
  273.     }
  274. }
  275.  
  276. /*----------------------------------------------------------------------*/
  277.  
  278. char*
  279. fs_strncpy(s1, s2, n)
  280.      char* s1;
  281.      char* s2;
  282.      long n;
  283. /* like strncpy except that it guarentees that the destination string ends with a NULL at position n.
  284.  */
  285. {
  286.   s1[n-1] = '\0';
  287.   return(strncpy(s1, s2, n - 1));
  288. }
  289.  
  290. /*----------------------------------------------------------------------*/
  291.  
  292. typedef long (longfunc) _AP((long c));
  293.  
  294. char*
  295. strtokf(s1,isDelimiter)
  296. char* s1;
  297. longfunc *isDelimiter; /* really *isDelimiter() */
  298.  
  299. /* This function is exactly like strtok, except that instead of passing a 
  300.    delimiter string, you pass a function that decides if a character is 
  301.    a delimiter or not, returning IS_DELIMITER or NOT_DELIMITER respecively.
  302.    Note that passing a NULL delimiter function will cause the last delimiter
  303.    to be used.
  304.  */
  305. {
  306.   static char* searchStr = NULL;
  307.   static longfunc *delimiterFunc;
  308.   long i;
  309.   char* startTok = NULL;
  310.  
  311.   if (s1 != NULL)        /* passing s1 = NULL says use the last pos */
  312.     searchStr = s1;
  313.     
  314.   if (isDelimiter != NULL)
  315.     delimiterFunc = isDelimiter;
  316.    
  317.   if (searchStr == NULL || searchStr[0] == '\0')
  318.     return(NULL);        /* nothing left to search */
  319.     
  320.   if (delimiterFunc == NULL)
  321.     return(NULL);        /* no delimiter to search with */
  322.     
  323.   /* find the start of the next token */
  324.   for (i = 0; searchStr[i] != '\0'; i++)
  325.     { if ((*delimiterFunc)((long)searchStr[i]) == NOT_DELIMITER)
  326.     break;
  327.     }
  328.   
  329.   if (searchStr[i] == '\0') 
  330.     return(NULL);        /* read to end of search string */
  331.   else
  332.     startTok = searchStr + i;    /* remember the starting point for this token*/
  333.     
  334.   /* find the end of the next token */
  335.   for (; searchStr[i] != '\0'; i++)
  336.     { if ((*delimiterFunc)((long)searchStr[i]) == IS_DELIMITER)
  337.     break;
  338.     }
  339.    
  340.   /* if the end is a delimiter (and not just the end of the search string)
  341.      replace it with '\0', and put searchStr just beyond it, otherwise
  342.      put searchStr at the terminator. */
  343.   if (searchStr[i] != '\0')
  344.     { searchStr[i] = '\0';
  345.       searchStr = searchStr + i + 1;
  346.     }
  347.   else
  348.     searchStr = searchStr + i;
  349.    
  350.   return(startTok);
  351. }
  352.  
  353. /*----------------------------------------------------------------------*/
  354.  
  355. char*
  356. strtokf_isalnum(s1)
  357. char* s1;
  358.  
  359. /* 
  360.   This is a partially evaluated version of strtok_f
  361.  */
  362. {
  363.   static char* searchStr = NULL;
  364.   long i;
  365.   char* startTok = NULL;
  366.  
  367.   if (s1 != NULL)        /* passing s1 = NULL says use the last pos */
  368.     searchStr = s1;
  369.     
  370.    
  371.   if (searchStr == NULL || searchStr[0] == '\0')
  372.     return(NULL);        /* nothing left to search */
  373.     
  374.     
  375.   /* find the start of the next token */
  376.   for (i = 0; searchStr[i] != '\0'; i++)
  377.     { if (isalnum(searchStr[i]))
  378.     break;
  379.     }
  380.   
  381.   if (searchStr[i] == '\0') 
  382.     return(NULL);        /* read to end of search string */
  383.   else
  384.     startTok = searchStr + i;    /* remember the starting point for this token*/
  385.     
  386.   /* find the end of the next token */
  387.   for (; searchStr[i] != '\0'; i++)
  388.     { if (!isalnum(searchStr[i]))
  389.     break;
  390.     }
  391.    
  392.   /* if the end is a delimiter (and not just the end of the search string)
  393.      replace it with '\0', and put searchStr just beyond it, otherwise
  394.      put searchStr at the terminator. */
  395.   if (searchStr[i] != '\0')
  396.     { searchStr[i] = '\0';
  397.       searchStr = searchStr + i + 1;
  398.     }
  399.   else
  400.     searchStr = searchStr + i;
  401.    
  402.   return(startTok);
  403. }
  404.  
  405. /*----------------------------------------------------------------------*/
  406.  
  407. #ifdef ANSI_LIKE /* use ansi varargs */
  408.  
  409. long
  410. cprintf(boolean print, char* format, ...)
  411. /* just like printf, but only prints if the first argument = 1 */
  412. {
  413.   va_list ap;            /* the variable arguments */
  414.   if (print == 1)
  415.     { long res;
  416.       va_start(ap,format);    /* init ap */
  417.       res = vprintf(format,ap);    /* print the contents */
  418.       va_end(ap);        /* free ap */
  419.       return(res);
  420.     }
  421.   else
  422.     return(0);
  423. }
  424.  
  425. #else /* use k&r varargs */
  426.  
  427. long
  428. cprintf(va_alist)
  429. va_dcl
  430. /* just like printf, but only prints if the first argument = 1 */
  431. {
  432.   va_list ap;            /* the variable arguments */
  433.   boolean print;
  434.   long res;
  435.  
  436.   va_start(ap);            /* init ap */
  437.  
  438.   print = va_arg(ap,boolean);    /* get the condition */
  439.  
  440.   if (print == 1)
  441.     { char* format = va_arg(ap,char*); /* get the format */
  442.       res = vprintf(format,ap);    /* print the contents */
  443.     }
  444.   else
  445.     res = 0;
  446.  
  447.   va_end(ap);            /* free ap */
  448.  
  449.   return(res);
  450. }
  451.  
  452.   
  453. #endif
  454.  
  455. extern char* log_file_name;
  456. extern FILE* logfile;
  457.  
  458. /* waislog - a new and improved logging facility.
  459.    first two arguments are important, the rest is text.
  460.  
  461.    arg1: priority.  If priority > log_level (some global), output this
  462.    message
  463.  
  464.    arg2: message code.  This is the kind of message (search, retrieval, etc).
  465. */
  466.  
  467. #ifdef ANSI_LIKE /* use ansi varargs */
  468.  
  469. void
  470. waislog(long priority, long message, char* format, ...)
  471. /* just like printf, but prints to the logfile, with PID and time. */
  472. {
  473.   va_list ap;            /* the variable arguments */
  474.  
  475.   if(priority <= wais_log_level) {
  476.  
  477.     if(logfile == NULL && log_file_name != NULL)
  478.       logfile = fopen(log_file_name, "a");
  479.  
  480.     if(logfile) {
  481.       va_start(ap, format);
  482.  
  483.       fprintf(logfile, "%d: %d: %s: %d: ", wais_pid, log_line++, printable_time(), message);
  484.  
  485.       vfprintf(logfile, format,ap); /* print the contents */
  486.       fprintf(logfile, "\n");
  487.       fflush(logfile);
  488.       va_end(ap);        /* free ap */
  489.     }
  490.  
  491.     if(logfile != NULL && logfile != stderr) {
  492.       fclose(logfile);
  493.       logfile = NULL;
  494.     }
  495.   }
  496. }
  497.  
  498. #else /* use k&r varargs */
  499.  
  500. void
  501. waislog(va_alist)
  502. va_dcl
  503. /* just like printf, but prints to the logfile, with PID and time. */
  504. {
  505.   va_list ap;            /* the variable arguments */
  506.   char* format;
  507.   static long line = 0;
  508.   int priority, message;
  509.  
  510.   va_start(ap);            /* init ap */
  511.  
  512.   priority = va_arg(ap, int);
  513.  
  514.   if(priority <= wais_log_level) {
  515.  
  516.     if(logfile == NULL && log_file_name != NULL)
  517.       logfile = fopen(log_file_name, "a");
  518.  
  519.   
  520.     if(logfile) {
  521.       message = va_arg(ap, int);
  522.  
  523.       fprintf(logfile, "%d: %d: %s: %d: ", wais_pid, line++, printable_time(), message);
  524.  
  525.       format = va_arg(ap,char*); /* get the format */
  526.  
  527.       vfprintf(logfile, format,ap); /* print the contents */
  528.       fprintf(logfile, "\n");
  529.       fflush(logfile);
  530.     }
  531.  
  532.     if(logfile != NULL && logfile != stderr) {
  533.       fclose(logfile);
  534.       logfile = NULL;
  535.     }
  536.   }
  537.   va_end(ap);            /* free ap */
  538. }
  539.  
  540. #endif /* ANSI_LIKE */
  541.   
  542. /*----------------------------------------------------------------------*/
  543.  
  544. void
  545. warn(message)
  546. char* message;
  547.  
  548. {
  549. #ifdef THINK_C
  550.   Debugger();
  551. #else
  552.   printf("%s\n<press return to continue>\n",message);
  553.   getchar();
  554. #endif
  555. }
  556.  
  557. /*----------------------------------------------------------------------*/
  558. boolean substrcmp(string1,string2)
  559. char *string1, *string2;
  560. {
  561.   /* compares the strings up until one of then ends.
  562.    * returns true if they are the same, false if not.
  563.    */
  564.   register char *a, *b;
  565.   
  566.   a = string1;
  567.   b = string2;
  568.   
  569.   while (*a && *b) 
  570.     if(*a++ != *b++) 
  571.       return false;
  572.   return true;
  573. }
  574.  
  575. /*----------------------------------------------------------------------*/
  576.  
  577. char *printable_time()
  578.   static char *string;
  579.   time_t tptr;
  580.   time(&tptr);
  581.   string = ctime(&tptr);
  582.   if(string){
  583.     if(string[strlen(string)-1] == '\n')
  584.       string[strlen(string)-1] = '\0';   
  585.     return(string+4);
  586.   }
  587.   else
  588.     return("Time Unknown");
  589. }
  590.  
  591. /*----------------------------------------------------------------------*/
  592.  
  593. char char_downcase(long_ch)
  594. unsigned long long_ch;
  595. {
  596.   unsigned char ch = long_ch & 0xFF; /* just want one byte */
  597.   /* when ansi is the way of the world, this can be tolower */
  598.   return (((ch >= 'A') && (ch <= 'Z')) ? (ch + 'a' -'A') : ch);
  599. }
  600.  
  601. char *string_downcase(word)
  602. char *word;
  603. {
  604.   long i = 0;
  605.  
  606.   if (word == NULL)
  607.     return(NULL);
  608.  
  609.   while(word[i] != '\0')
  610.    { word[i] = char_downcase((unsigned long)word[i]);
  611.      i++;
  612.    }
  613.  
  614.   return(word);
  615. }
  616.  
  617. /*----------------------------------------------------------------------*/
  618.  
  619.  
  620. /* parsing arguments functions */
  621.  
  622. char *next_arg(argc,argv)
  623. int *argc;
  624. char ***argv;
  625.  
  626.      /* Returns NULL when it is out of arguments,
  627.         This side effects both argc and argv.  argc always contains the number
  628.     of arguments left.
  629.     The first returned is the command name. 
  630.     */
  631. {
  632.   if((*argc)-- > 0)
  633.     return(*((*argv)++));
  634.   else
  635.     return(NULL);
  636. }
  637.  
  638. /*----------------------------------------------------------------------*/
  639.  
  640. char *peek_arg(argc,argv)
  641. int *argc;
  642.     char ***argv;
  643.  
  644.      /* Returns the next argument without popping it.
  645.        Returns NULL when it is out of arguments.
  646.        */
  647. {
  648.   if((*argc) > 0)
  649.     return(**argv);
  650.   else
  651.     return(NULL);
  652. }
  653.  
  654. /*----------------------------------------------------------------------*/
  655.  
  656.  
  657. #ifdef THINK_C
  658. #include <EventMgr.h>
  659. #undef MAX_FILE_NAME_LEN 
  660. #ifdef WAIStation
  661. #include "CRetrievalApp.h"
  662. #endif /* def WAIStation */
  663. #endif /* def THINK_C */
  664.  
  665. void
  666. beFriendly()
  667. /* this routine is called during time intensive operations
  668.    on single processing machines (macs and DOS).  It gives
  669.    time to other processes
  670.  */
  671. #ifdef never
  672. #ifdef THINK_C
  673.    EventRecord      macEvent;    /* an event */
  674.  
  675.    static RgnHandle    mouseRgn = NULL; /* region for mouse moved events */
  676.    long                sleepTime;     /* max time between events */
  677.    
  678. #ifdef WAIStation
  679.    gApplication->FrobWaitCursor();
  680. #endif /* def WAIStation */
  681.    
  682.    if (mouseRgn == NULL)
  683.      mouseRgn = NewRgn(); /* do we need to set its value? */
  684.      
  685.    sleepTime = 5; /* arbitrary - a tech note recommends < 50 */
  686.    
  687.    WaitNextEvent(everyEvent,&macEvent,sleepTime,mouseRgn); 
  688. #endif /* def THINK_C */
  689. #endif
  690. }
  691.  
  692. #ifdef BSD
  693. #define NEED_VPRINTF
  694. #endif
  695.  
  696. #ifdef NEED_VPRINTF
  697. /* Portable vsprintf  by Robert A. Larson <blarson@skat.usc.edu> */
  698.  
  699. /* Copyright 1989 Robert A. Larson.
  700.  * Distribution in any form is allowed as long as the author
  701.  * retains credit, changes are noted by their author and the
  702.  * copyright message remains intact.  This program comes as-is
  703.  * with no warentee of fitness for any purpouse.
  704.  *
  705.  * Thanks to Doug Gwen, Chris Torek, and others who helped clarify
  706.  * the ansi printf specs.
  707.  *
  708.  * Please send any bug fixes and improvments to blarson@skat.usc.edu .
  709.  * The use of goto is NOT a bug.
  710.  */
  711.  
  712. /* Feb    7, 1989        blarson        First usenet release */
  713.  
  714. /* This code implements the vsprintf function, without relying on
  715.  * the existance of _doprint or other system specific code.
  716.  *
  717.  * Define NOVOID if void * is not a supported type.
  718.  *
  719.  * Two compile options are available for efficency:
  720.  *    INTSPRINTF    should be defined if sprintf is int and returns
  721.  *            the number of chacters formated.
  722.  *    LONGINT        should be defined if sizeof(long) == sizeof(int)
  723.  *
  724.  *    They only make the code smaller and faster, they need not be
  725.  *    defined.
  726.  *
  727.  * UNSIGNEDSPECIAL should be defined if unsigned is treated differently
  728.  * than int in argument passing.  If this is definded, and LONGINT is not,
  729.  * the compiler must support the type unsingned long.
  730.  *
  731.  * Most quirks and bugs of the available sprintf fuction are duplicated,
  732.  * however * in the width and precision fields will work correctly
  733.  * even if sprintf does not support this, as will the n format.
  734.  *
  735.  * Bad format strings, or those with very long width and precision
  736.  * fields (including expanded * fields) will cause undesired results.
  737.  */
  738.  
  739. #ifdef OSK        /* os9/68k can take advantage of both */
  740. #define LONGINT
  741. #define INTSPRINTF
  742. #endif
  743.  
  744. /* This must be a typedef not a #define! */
  745. #ifdef NOVOID
  746. typedef char *pointer;
  747. #else
  748. typedef void *pointer;
  749. #endif
  750.  
  751. #ifdef    INTSPRINTF
  752. #define Sprintf(string,format,arg)    (sprintf((string),(format),(arg)))
  753. #else
  754. #define Sprintf(string,format,arg)    (\
  755.     sprintf((string),(format),(arg)),\
  756.     strlen(string)\
  757. )
  758. #endif
  759.  
  760. typedef int *intp;
  761.  
  762. int vsprintf(dest, format, args)
  763. char *dest;
  764. register char *format;
  765. va_list args;
  766. {
  767.     register char *dp = dest;
  768.     register char c;
  769.     register char *tp;
  770.     char tempfmt[64];
  771. #ifndef LONGINT
  772.     int longflag;
  773. #endif
  774.  
  775.     tempfmt[0] = '%';
  776.     while( (c = *format++) != 0) {
  777.     if(c=='%') {
  778.         tp = &tempfmt[1];
  779. #ifndef LONGINT
  780.         longflag = 0;
  781. #endif
  782. continue_format:
  783.         switch(c = *format++) {
  784.         case 's':
  785.             *tp++ = c;
  786.             *tp = '\0';
  787.             dp += Sprintf(dp, tempfmt, va_arg(args, char *));
  788.             break;
  789.         case 'u':
  790.         case 'x':
  791.         case 'o':
  792.         case 'X':
  793. #ifdef UNSIGNEDSPECIAL
  794.             *tp++ = c;
  795.             *tp = '\0';
  796. #ifndef LONGINT
  797.             if(longflag)
  798.             dp += Sprintf(dp, tempfmt, va_arg(args, unsigned long));
  799.             else
  800. #endif
  801.             dp += Sprintf(dp, tempfmt, va_arg(args, unsigned));
  802.             break;
  803. #endif
  804.         case 'd':
  805.         case 'c':
  806.         case 'i':
  807.             *tp++ = c;
  808.             *tp = '\0';
  809. #ifndef LONGINT
  810.             if(longflag)
  811.             dp += Sprintf(dp, tempfmt, va_arg(args, long));
  812.             else
  813. #endif
  814.             dp += Sprintf(dp, tempfmt, va_arg(args, int));
  815.             break;
  816.         case 'f':
  817.         case 'e':
  818.         case 'E':
  819.         case 'g':
  820.         case 'G':
  821.             *tp++ = c;
  822.             *tp = '\0';
  823.             dp += Sprintf(dp, tempfmt, va_arg(args, double));
  824.             break;
  825.         case 'p':
  826.             *tp++ = c;
  827.             *tp = '\0';
  828.             dp += Sprintf(dp, tempfmt, va_arg(args, pointer));
  829.             break;
  830.         case '-':
  831.         case '+':
  832.         case '0':
  833.         case '1':
  834.         case '2':
  835.         case '3':
  836.         case '4':
  837.         case '5':
  838.         case '6':
  839.         case '7':
  840.         case '8':
  841.         case '9':
  842.         case '.':
  843.         case ' ':
  844.         case '#':
  845.         case 'h':
  846.             *tp++ = c;
  847.             goto continue_format;
  848.         case 'l':
  849. #ifndef LONGINT
  850.             longflag = 1;
  851.             *tp++ = c;
  852. #endif
  853.             goto continue_format;
  854.         case '*':
  855.             tp += Sprintf(tp, "%d", va_arg(args, int));
  856.             goto continue_format;
  857.         case 'n':
  858.             *va_arg(args, intp) = dp - dest;
  859.             break;
  860.         case '%':
  861.         default:
  862.             *dp++ = c;
  863.             break;
  864.         }
  865.     } else *dp++ = c;
  866.     }
  867.     *dp = '\0';
  868.     return dp - dest;
  869. }
  870.  
  871.  
  872. int vfprintf(dest, format, args)
  873. FILE *dest;
  874. register char *format;
  875. va_list args;
  876. {
  877.     register char c;
  878.     register char *tp;
  879.     register int count = 0;
  880.     char tempfmt[64];
  881. #ifndef LONGINT
  882.     int longflag;
  883. #endif
  884.  
  885.     tempfmt[0] = '%';
  886.     while(c = *format++) {
  887.     if(c=='%') {
  888.         tp = &tempfmt[1];
  889. #ifndef LONGINT
  890.         longflag = 0;
  891. #endif
  892. continue_format:
  893.         switch(c = *format++) {
  894.         case 's':
  895.             *tp++ = c;
  896.             *tp = '\0';
  897.             count += fprintf(dest, tempfmt, va_arg(args, char *));
  898.             break;
  899.         case 'u':
  900.         case 'x':
  901.         case 'o':
  902.         case 'X':
  903. #ifdef UNSIGNEDSPECIAL
  904.             *tp++ = c;
  905.             *tp = '\0';
  906. #ifndef LONGINT
  907.             if(longflag)
  908.             count += fprintf(dest, tempfmt, va_arg(args, unsigned long));
  909.             else
  910. #endif
  911.             count += fprintf(dest, tempfmt, va_arg(args, unsigned));
  912.             break;
  913. #endif
  914.         case 'd':
  915.         case 'c':
  916.         case 'i':
  917.             *tp++ = c;
  918.             *tp = '\0';
  919. #ifndef LONGINT
  920.             if(longflag)
  921.             count += fprintf(dest, tempfmt, va_arg(args, long));
  922.             else
  923. #endif
  924.             count += fprintf(dest, tempfmt, va_arg(args, int));
  925.             break;
  926.         case 'f':
  927.         case 'e':
  928.         case 'E':
  929.         case 'g':
  930.         case 'G':
  931.             *tp++ = c;
  932.             *tp = '\0';
  933.             count += fprintf(dest, tempfmt, va_arg(args, double));
  934.             break;
  935.         case 'p':
  936.             *tp++ = c;
  937.             *tp = '\0';
  938.             count += fprintf(dest, tempfmt, va_arg(args, pointer));
  939.             break;
  940.         case '-':
  941.         case '+':
  942.         case '0':
  943.         case '1':
  944.         case '2':
  945.         case '3':
  946.         case '4':
  947.         case '5':
  948.         case '6':
  949.         case '7':
  950.         case '8':
  951.         case '9':
  952.         case '.':
  953.         case ' ':
  954.         case '#':
  955.         case 'h':
  956.             *tp++ = c;
  957.             goto continue_format;
  958.         case 'l':
  959. #ifndef LONGINT
  960.             longflag = 1;
  961.             *tp++ = c;
  962. #endif
  963.             goto continue_format;
  964.         case '*':
  965.             tp += Sprintf(tp, "%d", va_arg(args, int));
  966.             goto continue_format;
  967.         case 'n':
  968.             *va_arg(args, intp) = count;
  969.             break;
  970.         case '%':
  971.         default:
  972.             putc(c, dest);
  973.             count++;
  974.             break;
  975.         }
  976.     } else {
  977.         putc(c, dest);
  978.         count++;
  979.     }
  980.     }
  981.     return count;
  982. }
  983.  
  984. vprintf(format, args)
  985. char *format;
  986. va_list args;
  987. {
  988.     return vfprintf(stdout, format, args);
  989. }
  990.  
  991. #endif
  992.  
  993.  
  994. /*----------------------------------------------------------------------*/
  995.